#ifndef __DEVICE_H
#define __DEVICE_H
#include "stdtype.h"
#include "error.h"
#include "mutex.h"
#include "compiler.h"
#include "carray.h"

/* the limit length of device name */
#define MX_DEVICE_NAME_LEN 16

struct mx_device;
typedef struct mx_device mx_device_t, *mx_device_pt;

/**
 * the descriptor of device information
 */
typedef struct
{
    char name[MX_DEVICE_NAME_LEN];      // device name
    char drvname[MX_DEVICE_NAME_LEN];   // the driver name for match operation
    mx_uint8_t chart[];                 // the structure chart of device
} mx_packed mx_device_data_t, *mx_device_data_pt;

/**
 * the descriptor of device operations
 */
typedef struct
{
    mx_err_t (*open) (mx_device_pt pdev);
    void (*close) (mx_device_pt pdev);
    mx_size_t (*read) (mx_device_pt pdev, mx_void_pt buf, mx_size_t size);
    mx_size_t (*write) (mx_device_pt pdev, mx_void_pt data, mx_size_t size);
    mx_err_t (*ctrl) (mx_device_pt pdev, mx_size_t ctrl, mx_void_pt arg);
} mx_device_ops_t, *mx_device_ops_pt;

/**
 * the descriptor of device
 */
struct mx_device
{
    mx_bool_t isopen;           // mark the device opened or not
    mx_bool_t isdirect;         // determines wheter the device depends on the driver
    mx_usize_t oc;              // record the totle count of read and write operations

    /* the dependency source of device */
    union
    {
        mx_device_ops_pt ops;   // direct operations
        mx_void_pt drv;         // the matched driver
    } rely;

    mx_carray_node_t node;      // an node of device list (not matched)
    mx_mutex_t mutex;           // for access(open/read/write/close/ctrl) operations
    mx_size_t seek;
    mx_void_pt rtdata;          // the information witch generated in runtime (for driver)
    mx_device_data_pt data;     // the information of the device for driver
};

/* mount a device to system */
void mx_device_mount (mx_device_pt pdev, mx_device_data_pt data, mx_device_ops_pt ops);
/* umount a device from system */
mx_err_t mx_device_umount (mx_device_pt pdev);
/* get the count of device in system */
mx_usize_t mx_device_count ();
/* get the device by name */
mx_device_pt mx_device_get (mx_string_pt name);
/* open a device */
mx_err_t mx_device_open (mx_device_pt pdev);
/* close a device */
void mx_device_close (mx_device_pt pdev);
/* read data from device */
mx_size_t mx_device_read (mx_device_pt pdev, mx_void_pt buf, mx_size_t size);
/* write data to a device */
mx_size_t mx_device_write (mx_device_pt pdev, mx_void_pt data, mx_size_t size);
/* control a device */
mx_err_t mx_device_ctrl (mx_device_pt pdev, mx_size_t ctrl, mx_void_pt arg);

#endif
